function isObject(target) {
  return Object.prototype.toString.call(target) === '[object Object]';
}
function isArray(target) {
  return Object.prototype.toString.call(target) === '[object Array]';
}
function isString(target) {
  return Object.prototype.toString.call(target) === '[object String]';
}
function getBaseConfig(node) {
  const { shape, tooltip, x: tempX, y: tempY, size, id, position, data, form, initialization, component, attrs } = node;

  // eslint-disable-next-line init-declarations
  let width;
  // eslint-disable-next-line init-declarations
  let height;
  let positionX = tempX;
  let positionY = tempY;
  const temForm = form;
  const temShape = shape;
  const temTooltip = tooltip;
  let temNodeType = component;
  if (data && data.nodeType) {
    temNodeType = data.nodeType;
  }
  if (size) {
    if (isObject(size)) {
      width = size.width;
      height = size.height;
    }
  }
  if (isObject(position)) {
    positionX = position.x;
    positionY = position.y;
  }

  return {
    type: temShape,
    label: temTooltip,
    x: positionX,
    y: positionY,
    width,
    height,
    id,
    component: temNodeType,
    data: {
      nodeType: temNodeType,
      initialization,
      tooltip: temTooltip,
      ...temForm,
      ...data
    },
    attrs
  };
}

function getVueNode(node, comp) {
  const { x, y, id, data, attrs } = getBaseConfig(node);
  const isText = ['text'].includes(comp);
  // 所有节点默认尺寸
  let width = 40;
  let height = 40;
  // 人工节点尺寸
  if (['task'].includes(comp)) {
    width = 132;
    height = 72;
  } else if (isText) {
    // 文本框节点尺寸
    width = node.size?.width;
    height = node.size?.height;
  }
  const portAttr = {
    circle: {
      dataClass: 'choice-point',
      // 链接桩半径越大，连线起始点与节点边框的距离越大
      r: 1,
      magnet: true,
      stroke: '#5b8ffa',
      strokeWidth: 1,
      fill: '#fff'
    }
  };
  const normalNodePorts = {
    groups: {
      port_t: {
        attrs: portAttr,
        position: {
          name: 'ellipseSpread',
          args: {
            start: 0
          }
        }
      }
      // port_r: {
      //   attrs: portAttr,
      //   position: {
      //     name: 'ellipseSpread',
      //     args: {
      //       start: 90
      //     }
      //   }
      // },
      // port_b: {
      //   attrs: portAttr,
      //   position: {
      //     name: 'ellipseSpread',
      //     args: {
      //       start: 180
      //     }
      //   }
      // },
      // port_l: {
      //   attrs: portAttr,
      //   position: {
      //     name: 'ellipseSpread',
      //     args: {
      //       start: 270
      //     }
      //   }
      // }
    },
    items: [
      { group: 'port_t', id: 'p_top' }
      // { group: 'port_r', id: 'p_right' },
      // { group: 'port_b', id: 'p_bottom' },
      // { group: 'port_l', id: 'p_left' }
    ]
  };
  return {
    id,
    shape: node.shape,
    x,
    y,
    width,
    height,
    zIndex: 100,
    data,
    component: comp,
    ports: isText ? {} : normalNodePorts,
    attrs
  };
}

/** 实例侧流程连线常规属性 */
const lineAttr = {
  stroke: '#1ea087',
  strokeWidth: 1.5,
  targetMarker: {
    name: 'block',
    args: {
      size: '6'
    }
  },
  strokeDasharray: 0, // 虚线
  style: {
    animation: 'ant-line 30s infinite linear'
  }
};
function getEdgeNode(edge) {
  let edgeStatus = {};
  if (edge.data.edgeStatus && edge.data.edgeStatus === 'norun') {
    edgeStatus = {
      stroke: 'rgba(0,0,0,0.2)'
    };
  }

  // 退回、拿回、跳转的流转线 标色
  const isJumpEdge = edge.data.edgeStatus && edge.data.edgeStatus === 'jump';
  if (isJumpEdge) {
    edgeStatus = {
      stroke: '#B00015'
    };
  }
  // 流程图中的常规模板线
  return {
    zIndex: isJumpEdge ? 1 : -1,
    attrs: {
      line: { ...lineAttr, ...edgeStatus }
    },
    ...edge,
    target: isJumpEdge
      ? {
        cell: edge.target.cell,
        // 退回、拿回、跳转的流转线 设置为链接桩上进上出，不设置锚点、连接点
        port: isJumpEdge ? 'p_top' : ''
      }
      : {
        cell: edge.target.cell,
        anchor: 'orth',
        connectionPoint: { name: 'boundary' }
      },
    source: {
      cell: edge.source.cell,
      // 退回、拿回、跳转的流转线 设置为链接桩上进上出，不设置锚点、连接点
      port: isJumpEdge ? 'p_top' : ''
    },
    connector: {
      name: 'rounded',
      args: { radius: 4 }
    }
  };
}

/**
 * 冻结画布
 */
function freezeGraph(graph) {
  const cells = graph.getCells();
  if (cells.length) {
    cells.forEach((cell) => {
      cell.removeTools();
      cell.setData({ disableMove: true });
    });
  }
}

/**
 * 解冻
 */
function unfreezeGraph(graph) {
  const cells = graph.getCells();
  if (cells.length) {
    cells.forEach((cell) => {
      cell.setData({ disableMove: false });
    });
  }
}

/** json格式化 */
function fmtJSON(target) {
  try {
    if (isString(target)) return JSON.parse(target);
    if (isArray(target)) {
      return target.map((item) => {
        if (isObject(item)) return item;
        return JSON.parse(item);
      });
    }
    if (isObject(target)) return target;

    return false;
  } catch (err) {
    return {};
  }
}

function getNodeJSON(nodes) {
  const nodeList = [];
  for (let i = 0; i < nodes.length; i++) {
    const node = nodes[i];
    const nodeJSON = fmtJSON(node);
    const nodeType = nodeJSON.component;
    if (!nodeType) {
      return;
    }
    nodeList.push(getVueNode(nodeJSON, nodeType));
  }
  // eslint-disable-next-line consistent-return
  return nodeList;
}

function getEdgeJSON(edges) {
  const edgeList = [];
  for (let i = 0; i < edges.length; i++) {
    const edge = edges[i];
    const edgeJSON = fmtJSON(edge);
    edgeList.push(getEdgeNode(edgeJSON));
  }
  return edgeList;
}

/**
 * 反序列化
 * 按照指定的 JSON 数据渲染节点和边。
 */
function fromJSON(graph, nodes, edges) {
  if (!isArray(nodes) || !isArray(edges)) {
    return;
  }

  graph.fromJSON({
    nodes: getNodeJSON(nodes),
    edges: getEdgeJSON(edges)
  });
}

export const onlyLook = (bool, graph) => {
  if (!graph) return;
  if (bool) freezeGraph(graph);
  else unfreezeGraph(graph);
};

export const initDefaultData = (nodes, edges, graph) => {
  if (!graph) return;
  fromJSON(graph, nodes, edges);
};

// 初始化内部nodeArr属性
export const fixFireFox = (nodeArrs) => {
  if (!nodeArrs) return;

  if (navigator.userAgent.indexOf('Firefox') > 0) {
    nodeArrs.forEach((node) => {
      document.querySelector(`[data-cell-id="${node.id}"]`).style.display = 'none';
    });

    setTimeout(() => {
      nodeArrs.forEach((node) => {
        document.querySelector(`[data-cell-id="${node.id}"]`).style.display = 'block';
      });
    }, 0);
  }
};
